(function(factory) {
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    } else if (typeof define === 'function' && define.cmd) {
        define(function(require, exports, moudles) {
            factory(require('jquery'));
            return jQuery;
        });
    } else {
        factory(jQuery);
    };
}(function($) {
    "use strict";

    /*! String 对象方法扩展
     * by KingRenner 2015-05-10
     */
    $.extend(String.prototype, {

        Trim: function() {
            return this.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, '');
        },
        TrimAll: function() {
            var result = this.replace(/^\s+/g, "");
            result = result.replace(/\s+$/g, "");
            result = result.replace(/\s+/g, "");
            result = result.replace(/^(\s*\S*(\s+\S+)*)\s*$/, '$1');
            return result;
        },
        strLen: function() {
            var __arr = this.match(/[^\x00-\xff]/ig);
            return this.length + (__arr == null ? 0 : __arr.length);
        },
        Left: function(num, mode) {
            if (!/\d+/.test(num)) return (this);
            var str = this.substr(0, num);
            if (!mode) return str;
            var n = str.TLength() - str.length;
            num = num - parseInt(n / 2);
            return this.substr(0, num);
        },
        Right: function(num, mode) {
            if (!/\d+/.test(num)) return (this);
            var str = this.substr(this.length - num);
            if (!mode) return str;
            var n = str.TLength() - str.length;
            num = num - parseInt(n / 2);
            return this.substr(this.length - num);
        },
        Mid: function(startnum, endnum) {
            var str = this;
            if (str.length >= 0) {
                str = str.substr(startnum, endnum);
            }
            return str;
        },
        isPhone: function() {
            return (new RegExp(/(^([0-9]{3,4}[-])?\d{3,8}(-\d{1,6})?$)|(^\([0-9]{3,4}\)\d{3,8}(\(\d{1,6}\))?$)|(^\d{3,8}$)/).test(this));
        },
        isUrl: function() {
            return (new RegExp(/^[a-zA-z]+:\/\/([a-zA-Z0-9\-\.]+)([-\w .\/?%&=:]*)$/).test(this));
        }

    });
    
    /* mouse hover event */
    $.fn.hoverDelay = function(options) {
        var defaults = {
            hoverDuring: 200,
            outDuring: 200,
            hoverEvent: function() {
                $.noop();
            },
            outEvent: function() {
                $.noop();
            }
        };
        var sets = $.extend(defaults, options || {});
        var hoverTimer, outTimer;
        return $(this).each(function() {
            $(this).hover(function() {
                clearTimeout(outTimer);
                hoverTimer = setTimeout(sets.hoverEvent, sets.hoverDuring);
            }, function() {
                clearTimeout(hoverTimer);
                outTimer = setTimeout(sets.outEvent, sets.outDuring);
            });
        });
    }

    /* ############################## */
    /**
     * [zexJs] 浏览器检测模块
     */
    var __browser_class = function() {
        var agent = navigator.userAgent.toLowerCase(),
            opera = window.opera,
            browser = {
                //ie 检测当前浏览器是否为IE
                ie: /(msie\s|trident.*rv:)([\w.]+)/.test(agent),
                //opera 检测当前浏览器是否为Opera
                opera: (!!opera && opera.version),
                //webkit 检测当前浏览器是否是webkit内核的浏览器
                webkit: (agent.indexOf(' applewebkit/') > -1),
                //mac 检测当前浏览器是否是运行在mac平台下
                mac: (agent.indexOf('macintosh') > -1),
                //quirks 检测当前浏览器是否处于“怪异模式”下
                quirks: (document.compatMode == 'BackCompat')
            };
        //gecko 检测当前浏览器内核是否是gecko内核
        browser.gecko = (navigator.product == 'Gecko' && !browser.webkit && !browser.opera && !browser.ie);

        var version = 0;
        if (browser.ie) {
            var v1 = agent.match(/(?:msie\s([\w.]+))/);
            var v2 = agent.match(/(?:trident.*rv:([\w.]+))/);
            if (v1 && v2 && v1[1] && v2[1]) {
                version = Math.max(v1[1] * 1, v2[1] * 1);
            } else if (v1 && v1[1]) {
                version = v1[1] * 1;
            } else if (v2 && v2[1]) {
                version = v2[1] * 1;
            } else {
                version = 0;
            }

            browser.ie11Compat = document.documentMode == 11;
            /**
             * @property { boolean } ie9Compat 检测浏览器模式是否为 IE9 兼容模式
             * @warning 如果浏览器不是IE，则该值为undefined
             */
            browser.ie9Compat = document.documentMode == 9;
            /**
             * @property { boolean } ie8 检测浏览器是否是IE8浏览器
             * @warning 如果浏览器不是IE，则该值为undefined
             */
            browser.ie8 = !!document.documentMode;
            /**
             * @property { boolean } ie8Compat 检测浏览器模式是否为 IE8 兼容模式
             * @warning 如果浏览器不是IE，则该值为undefined
             */
            browser.ie8Compat = document.documentMode == 8;
            /**
             * @property { boolean } ie7Compat 检测浏览器模式是否为 IE7 兼容模式
             * @warning 如果浏览器不是IE，则该值为undefined
             */
            browser.ie7Compat = ((version == 7 && !document.documentMode) || document.documentMode == 7);
            /**
             * @property { boolean } ie6Compat 检测浏览器模式是否为 IE6 模式 或者怪异模式
             * @warning 如果浏览器不是IE，则该值为undefined
             */
            browser.ie6Compat = (version < 7 || browser.quirks);

            browser.ie9above = version > 8;

            browser.ie9below = version < 9;

            browser.ie11above = version > 10;

            browser.ie11below = version < 11;
        }

        //Gecko.
        if (browser.gecko) {
            var geckoRelease = agent.match(/rv:([\d\.]+)/);
            if (geckoRelease) {
                geckoRelease = geckoRelease[1].split('.');
                version = geckoRelease[0] * 10000 + (geckoRelease[1] || 0) * 100 + (geckoRelease[2] || 0) * 1;
            }
        }

        /**
         * @property { Number } chrome 检测当前浏览器是否为Chrome。如果是，则返回Chrome的大版本号
         * @warning 如果浏览器不是chrome，则该值为undefined
         */
        if (/chrome\/(\d+\.\d)/i.test(agent)) {
            browser.chrome = +RegExp['\x241'];
        }

        /**
         * @property { Number } safari 检测当前浏览器是否为Safari。如果是，则返回Safari的大版本号
         * @warning 如果浏览器不是safari，则该值为undefined
         */
        if (/(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(agent) && !/chrome/i.test(agent)) {
            browser.safari = +(RegExp['\x241'] || RegExp['\x242']);
        }

        //Opera 9.50+
        if (browser.opera)
            version = parseFloat(opera.version());

        //WebKit 522+ (Safari 3+)
        if (browser.webkit)
            version = parseFloat(agent.match(/ applewebkit\/(\d+)/)[1]);

        /**
         * @property { Number } version 检测当前浏览器版本号
         * @remind
         * <ul>
         *   <li>IE系列返回值为5,6,7,8,9,10等</li>
         *   <li>gecko系列会返回10900，158900等</li>
         *   <li>webkit系列会返回其build号 (如 522等)</li>
         * </ul>
         */
        browser.version = version;

        /**
         * @property { boolean } isCompatible 检测当前浏览器是否能够与zexJs良好兼容
         */
        browser.isCompatible = !browser.mobile && (
            (browser.ie && version >= 6) ||
            (browser.gecko && version >= 10801) ||
            (browser.opera && version >= 9.5) ||
            (browser.air && version >= 1) ||
            (browser.webkit && version >= 522) ||
            false);
        return browser;
    }();

    /* ############################## */
    /**
     * [zexJs] 常用正则模块
     */
    var __regular_class = {

        //[Rule]仅ACSII字符
        "ascii": /^[\x00-\xFF]+$/,
        "address": /^[A-Za-z0-9_()（）\#\-\u4e00-\u9fa5]+$/,
        //[Rule]仅中文
        "chinese": /^[\u4e00-\u9fa5]+$/,
        //[Rule]颜色
        "color": /^[a-fA-F0-9]{6}$/,
        "companyname": /^[A-Za-z0-9_()（）\-\u4e00-\u9fa5]+$/,
        "companysite": /^http[s]?:\/\/([\w-]+\.)+[\w-]+([\w-./?%&#=]*)?$/,
        //[Rule]Decmal浮点数
        "decmal": /^([+-]?)\d*\.\d+$/,
        //[Rule]正浮点数
        "decmal1": /^[1-9]\d*.\d*|0.\d*[1-9]\d*$/,
        //[Rule]负浮点数
        "decmal2": /^-([1-9]\d*.\d*|0.\d*[1-9]\d*)$/,
        "decmal3": /^-?([1-9]\d*.\d*|0.\d*[1-9]\d*|0?.0+|0)$/,
        //[Rule]非负浮点数（正浮点数 + 0）
        "decmal4": /^[1-9]\d*.\d*|0.\d*[1-9]\d*|0?.0+|0$/,
        //[Rule]非正浮点数（负浮点数 + 0）
        "decmal5": /^(-([1-9]\d*.\d*|0.\d*[1-9]\d*))|0?.0+|0$/,
        //[Rule]日期
        "date": /^\d{4}(\-|\/|\.)\d{1,2}\1\d{1,2}$/,
        //[Rule]单位名
        "deptname": /^[A-Za-z0-9_()（）\-\u4e00-\u9fa5]+$/,
        //[Rule]电子邮件
        "email": /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/,
        "en-int": /^[A-Za-z0-9]/,
        "fullNumber": /^[0-9]+$/,
        //[Rule]整数
        "intege": /^-?[1-9]\d*$/,
        //[Rule]正整数
        "intege1": /^[1-9]\d*$/,
        //[Rule]负整数
        "intege2": /^-[1-9]\d*$/,
        //[Rule]身份证
        "idcard": /^[1-9]([0-9]{14}|[0-9]{17})$/,
        //[Rule]IP地址（v4）
        "ip4": /^(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)$/,
        "letter": /^[A-Za-z]+$/,
        "letter_l": /^[a-z]+$/,
        "letter_u": /^[A-Z]+$/,
        //[Rule]手机
        "mobile": /^0?(13|15|18|14|17)[0-9]{9}$/,
        //[Rule]数字
        "num": /^([+-]?)\d*\.?\d+$/,
        //[Rule]正数（正整数 + 0）
        "num1": /^[1-9]\d*|0$/,
        //[Rule]负数（负整数 + 0）
        "num2": /^-[1-9]\d*|0$/,
        "picture": /(.*)\.(jpg|bmp|gif|ico|pcx|jpeg|tif|png|raw|tga)$/,
        "pub_account": /^[a-zA-Z]{1}([a-zA-Z0-9]|[._]){4,19}$/,
        "pub_pwd": /^[\w~!@#$%^&*()_+{}:<>?\-=[\];\.\/]{6,16}$/,
        "password": /^.*[A-Za-z0-9\w_-]+.*$/,
        "qq": /^[1-9]*[1-9][0-9]*$/,
        "rar": /(.*)\.(rar|zip|7zip|tgz)$/,
        "realname": /^[A-Za-z\u4e00-\u9fa5]+$/,
        //[Rule]电话号码（包括验证国内区号、国际区号、分机号）
        "tel": /^[0-9\-()（）]{7,18}$/,
        "url": /^http[s]?:\/\/([\w-]+\.)+[\w-]+([\w-./?%&=]*)?$/,
        //[Rule]邮政编码
        "zipcode": /^\d{6}$/

    };

    /* ############################## */
    /**
     * [zexJs] 静态工具函数
     */
    var __utils_class = {

        /**
         * 用给定的迭代器遍历数组或类数组对象
         * @param { Array } array 需要遍历的数组或者类数组
         * @param { Function } iterator 迭代器
           该方法接受两个参数，第一个参数是当前所处理的value，第二个参数是当前遍历对象的key
         * @param context iterator的上下文
         */
        each: function(obj, iterator, context) {
            if (obj == null) return;
            if (obj.length === +obj.length) {
                for (var i = 0, l = obj.length; i < l; i++) {
                    if (iterator.call(context, obj[i], i, obj) === false)
                        return false;
                }
            } else {
                for (var key in obj) {
                    if (obj.hasOwnProperty(key)) {
                        if (iterator.call(context, obj[key], key, obj) === false)
                            return false;
                    }
                }
            }
        },

        /**
         * 判断obj对象是否为空
         * @param { * } obj 需要判断的对象
         * @remind 如果判断的对象是NULL，将直接返回true；如果是数组且为空，返回true；如果是字符串，且字符串为空，
         *         返回true；如果是普通对象，且该对象没有任何实例属性，返回true
         * @return {Boolean} 对象是否为空
         */
        isNullOrEmpty: function(obj) {
            if (obj == null) return true;
            if (this.isArray(obj) || this.isString(obj)) return obj.length === 0;
            for (var key in obj)
                if (obj.hasOwnProperty(key)) return false;
            return true;
        },

        /**
         * 获取元素item数组array中首次出现的位置, 如果未找到item，则返回-1。通过start的值可以指定搜索的起始位置。
         * @method indexOf
         * @remind 该方法的匹配过程使用的是恒等“===”
         * @param { Array } array 需要查找的数组对象
         * @param { * } item 需要在目标数组中查找的值
         * @param { int } start 搜索的起始位置
         * @return { int } 返回item在目标数组array中的start位置之后首次出现的位置，如果在数组中未找到item，则返回-1
         */
        indexOf: function(array, item, start) {
            var index = -1;
            start = this.isNumber(start) ? start : 0;
            this.each(array, function(v, i) {
                if (i >= start && v === item) {
                    index = i;
                    return false;
                }
            });
            return index;
        },
        /**
         * 移除数组array中所有的元素item
         * @method removeItem
         * @param { Array } array 要移除元素的目标数组
         * @param { * } item 将要被移除的元素
         * @remind 该方法的匹配过程使用的是恒等“===”
         */
        removeItem: function(array, item) {
            for (var i = 0, l = array.length; i < l; i++) {
                if (array[i] === item) {
                    array.splice(i, 1);
                    i--;
                }
            }
        },

        /**
         * 过滤元素
         */
        filterTag: function(tag, tagetTagName) {
            if (!tag.tagName || tag.tagName.toLowerCase() != tagetTagName) {
                return null;
            }
            return $(tag);
        },

        /**
         * 仿C# format方法（KingRenner增强版）
         */
        format: function(obj, args) {
            if (arguments.length < 2) {
                return arguments[0];
            }

            var tempArgs = [],
                result = obj;
            for (var n = 1; n < arguments.length; n++) {
                tempArgs.push(arguments[n]);
            }
            // if (tempArgs.length == 0) {
            //  return "";
            // }
            if (arguments.length == 2 && $.isPlainObject(args)) {
                for (var key in args) {
                    var reg = new RegExp("({" + key + "})", "g");
                    result = result.replace(reg, args[key]);
                };
            } else {
                for (var i = 0; i < tempArgs.length; i++) {
                    if (tempArgs[i] != undefined) {
                        if ($.isPlainObject(tempArgs[i])) {
                            for (var k in tempArgs[i]) {
                                var re = new RegExp("({" + k + "})", "g");
                                result = result.replace(re, tempArgs[i][k]);
                            }
                        }
                        var reg = new RegExp("({)" + i + "(})", "gm");
                        result = result.replace(reg, tempArgs[i]);
                    }
                };
            }
            return result;
        },

        /**
         * 把rgb格式的颜色值转换成16进制格式
         * @method fixColor
         * @param { String } rgb格式的颜色值
         * @param { String }
         * @example
         * rgb(255,255,255)  => "#ffffff"
         */
        fixColor: function(name, value) {
            if (/color/i.test(name) && /rgba?/.test(value)) {
                var array = value.split(",");
                if (array.length > 3)
                    return "";
                value = "#";
                for (var i = 0, color; color = array[i++];) {
                    color = parseInt(color.replace(/[^\d]/gi, ''), 10).toString(16);
                    value += color.length == 1 ? "0" + color : color;
                }
                value = value.toUpperCase();
            }
            return value;
        },

        //过滤html标签
        filtrHtml: function(text) {
            text = text.replace(/<\/?[^>]*>/g, ""); //去除HTML Tag
            text = text.replace(/[ | ]*\n/g, "\n"); //去除行尾空白
            text = text.replace(/\n[\s| | ]*\r/g, "\n"); //去除多余空行
            return text;
        },

        King_LR: function(str, separator) {
            var n;
            var arr = new Array();
            n = str.indexOf(separator);
            if (n > -1) {
                arr[0] = str.Left(n);
                arr[1] = str.Mid(n + separator.length);
            } else {
                arr[0] = str;
                arr[1] = "";
            }
            return arr;
        },
        //取分隔符字符串的左边
        CLeft: function(str, separator) {
            return this.King_LR(str, separator)[0];
        },
        //取分隔符字符串的右边
        CRight: function(str, separator) {
            return this.King_LR(str, separator)[1];
        },

        /**
         * 获取Url参数
         * @param {String} p 参数名
         * @param {String} url 地址。如果为空，则默认浏览器地址栏
         */
        getQuery: function(p, url) {
            var oTHIS = this;
            if (oTHIS.isNullOrEmpty(url.toString())) {
                url = window.location.href + '';
            } else {
                url += '';
            }

            var reg = new RegExp("[?&](" + p + ")=([^&]+)", "i");
            var rlt = reg.exec(url);
            if (rlt) {
                return decodeURIComponent(rlt[2]);
            } else {
                return "";
            }
        },

        /**
         * 正则获取指定文件后缀
         */
        getFileExt: function(strfile) {
            var result = /\.[^\.]+$/.exec(strfile);
            return result;
        },

        /**
         * 将str中的html符号转义。将转义“'、&、<、"、>”五个字符
         */
        unhtml: function(str, reg) {
            return str ? str.replace(reg || /[&<">'](?:(amp|lt|quot|gt|#39|nbsp|#\d+);)?/g, function(a, b) {
                if (b) {
                    return a;
                } else {
                    return {
                        "'": '&#39;',
                        '&': '&amp;',
                        '<': '&lt;',
                        '"': '&quot;',
                        '>': '&gt;'
                    }[a];
                }
            }) : '';
        },
        /**
         * 将str中的转义字符还原成html字符
         */
        tohtml: function(str) {
            return str ? str.replace(/&((g|l|quo)t|amp|#39|nbsp);/g, function(m) {
                return {
                    '&#39;': "'",
                    '&amp;': '&',
                    '&lt;': '<',
                    '&quot;': '"',
                    '&gt;': '>',
                    '&nbsp;': ' '
                }[m];
            }) : '';
        },

        reloadVCode: function(ele, sUrl) {
            if ($.trim(ele) == "" || $.trim(sUrl) == "") {
                return false;
            }
            var _obj = document.getElementById(ele);
            _obj.setAttribute('src', sUrl + '?r=' + Math.random());
            _obj = null;
            return true;
        },

        /**
         * 验证时间格式 2009-02-11 00:00:00
         */
        isDateTime: function(str) {
            var reg = /^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/;
            var r = str.match(reg);
            if (r == null) return false;
            var d = new Date(r[1], r[3] - 1, r[4], r[5], r[6], r[7]);
            return (d.getFullYear() == r[1] && (d.getMonth() + 1) == r[3] && d.getDate() == r[4] && d.getHours() == r[5] && d.getMinutes() == r[6] && d.getSeconds() == r[7]);
        },
        //短时间，形如（13:04:06）
        isShortTime: function(str) {
            var a = str.match(/^(\d{1,2})(:)?(\d{1,2})\2(\d{1,2})$/);
            if (a == null) {
                //alert('输入的参数不是时间格式');
                return false;
            }
            if (a[1] > 24 || a[3] > 60 || a[4] > 60) {
                //alert("时间格式不对");
                return false
            }
            return true;
        },
        //短日期，形如（2003-12-05）
        isShortDate: function(str) {
            var r = str.match(/^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/);
            if (r == null) return false;
            var d = new Date(r[1], r[3] - 1, r[4]);
            return (d.getFullYear() == r[1] && (d.getMonth() + 1) == r[3] && d.getDate() == r[4]);
        },

        isTagName: function(e, whitelists) {
            e = $.event.fix(e);
            var target = e.target || e.srcElement;
            if (whitelists && $.inArray(target.tagName.toString().toUpperCase(), whitelists) == -1) {
                return false;
            }
            return true;
        },

        //信息提示，基于artDialog v6 -----------------------------
        artAlert: function(_dialog, _title, _content, _locked, _url, _callback) {
            var __this = this;
            if (!$.isFunction(_dialog)) {
                return;
            }
            var m_arguments = arguments.length,
                m_config = {
                    title: '提示',
                    content: '',
                    okValue: '确定',
                    ok: function() {},
                    onclose: function() {}
                };

            switch (typeof _title) {
                case 'string':
                    _title = $.trim(_title);
                    if (!__this.isNullOrEmpty(_title)) {
                        m_config.title = String(_title);
                    }
                    break;
                default:
                    break;
            }
            m_config.content = _content;

            _url = $.trim(_url);
            m_config.onclose = function() {
                if (_url == "back") {
                    history.back(-1);
                } else if (!__this.isNullOrEmpty(_url)) {
                    window.location.href = _url;
                } else {}

                if (m_arguments == 6 && $.isFunction(_callback)) {
                    _callback();
                }
            }

            var d = _dialog({
                id: 'dialogAlert1985929D',
                fixed: true,
                title: m_config.title,
                content: m_config.content,
                backdropBackground: '#000000',
                backdropOpacity: 0.5,
                okValue: m_config.okValue,
                ok: m_config.ok,
                onclose: m_config.onclose
            });
            if (_locked === 1) {
                d.showModal();
            } else {
                d.show();
            }
        }

    };
    //判断指定对象是否为（字符串/方法/数组/数字/正则对象/对象）
    __utils_class.each(['String', 'Function', 'Array', 'Number', 'RegExp', 'Object', 'Date'], function(v) {
        __utils_class['is' + v] = function(obj) {
            return Object.prototype.toString.apply(obj) == '[object ' + v + ']';
        }
    });

    /* ############################## */
    $.extend({
        zex: {

            browser: __browser_class,
            regular: __regular_class || {},
            utils: __utils_class || {},
            //加载Css
            loadCss: function(css) {
                var __this = this;
                css = String(css).Trim();
                if (!__this.utils.isNullOrEmpty(css)) {
                    var strcss = '<link rel="stylesheet" type="text/css" href="' + css + '" />';
                    if ($('base')[0]) {
                        $('base').before(strcss);
                    } else {
                        $('head').append(strcss);
                    }
                }
            },
            //检测是否移动设备来访
            browserRedirect: function() {
                var sUserAgent = navigator.userAgent.toLowerCase(),
                    bIsIpad = sUserAgent.match(/ipad/i) == "ipad",
                    bIsIphoneOs = sUserAgent.match(/iphone os/i) == "iphone os",
                    bIsMidp = sUserAgent.match(/midp/i) == "midp",
                    bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == "rv:1.2.3.4",
                    bIsUc = sUserAgent.match(/ucweb/i) == "ucweb",
                    bIsAndroid = sUserAgent.match(/android/i) == "android",
                    bIsCE = sUserAgent.match(/windows ce/i) == "windows ce",
                    bIsWM = sUserAgent.match(/windows mobile/i) == "windows mobile";
                if (bIsIpad || bIsIphoneOs || bIsMidp || bIsUc7 || bIsUc || bIsAndroid || bIsCE || bIsWM) {
                    return true;
                } else {
                    return false;
                }
            }

        }
    });

}));